package com.suray.basic.wcs.plc.core;

import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.enums.Network;
import com.suray.basic.wcs.plc.exception.PLCInterruptException;
import com.suray.basic.wcs.plc.pojo.DeviceBase;
import com.suray.basic.wcs.plc.pojo.PlcParam;
import com.suray.basic.wcs.plc.pojo.oper.*;
import com.suray.basic.wcs.plc.pojo.oper.lifter.ForkLifterOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.LifterOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.TwoDirectionRgvLifterOper;
import com.suray.basic.wcs.plc.pojo.oper.single.*;
import com.suray.basic.wcs.plc.pojo.oper.single.lifter.LifterBaseOper;
import com.suray.basic.wcs.plc.pojo.oper.single.lifter.LifterStationOper;
import com.suray.basic.wcs.plc.pojo.oper.single.lifter.LifterSystemOper;
import com.suray.basic.wcs.plc.utils.LongConnSendUtil;
import com.suray.basic.wcs.plc.utils.NetAddress;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.ParamConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author shaozn
 * @date 2020/2/10 - 15:08
 * @Description PLC 一个PLC代表一个电控柜，包含这个PLC模块下的所有设备
 */
public class Plc {
    private static Logger log = LoggerFactory.getLogger(Plc.class);

    public final static ConcurrentHashMap<String, String> PLC_INTERRUPT_CACHE = new ConcurrentHashMap<>();
    public final static ConcurrentHashMap<String, ConcurrentHashMap<String, String>> PLC_AUTOMATIC_DOOR_CACHE =
            new ConcurrentHashMap<String, ConcurrentHashMap<String, String>>();
    private static Map<NetAddress, Plc> plcMap = new HashMap<>();
    /**
     * PLC一次性读取个数
     */
    public final static int PLC_READ_MAX_NUM = 125;
    public static Map<String, DeviceBase> deviceBaseNameMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceBaseCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceStationCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceShapeCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceScannerCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceWeightCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceAutomaticDoorCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceAutoHoistOperCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceToothHoistOperCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceButtonCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceLifterCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceSystemCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceDishCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceTransCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceMonomerConveyorCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceShapeConveyorCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceScanCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceTransPlanterCoordMap = new ConcurrentHashMap<>();
    public static Map<String, Coord> lifterCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceAutoTraversingOperCoordMap = new ConcurrentHashMap<>();
    public static Map<Integer, Map<Location, Coord>> lifterLocationMap = new ConcurrentHashMap<>();
    //翻转机
    public static Map<Coord, DeviceBase> deviceTurnoverMachineOperCoordMap = new ConcurrentHashMap<>();
    public static Map<Coord, DeviceBase> deviceFoldingOperCoordMap = new ConcurrentHashMap<>();
    /**
     * 系统操作对象
     */
    public SystemOper systemBaseName;

    /**
     * 通讯
     */
    private ModbusUtil modbusUtil;
    /**
     * 缓存
     */
    private PlcWordCache plcCache;

    private Network plcStatus = Network.ON_LINE;

    //	每个PLC读取的起始地址位和最大地址位
    private PlcParam plcParam;

    private NetAddress netAddress;

    public PlcParam getPlcParam() {
        return plcParam;
    }


    private Plc(ModbusUtil modbusUtil, List<DeviceBase> deviceBases, PlcParam plcParam) {
        this.netAddress = modbusUtil.getNetAddress();
        this.plcCache = new PlcWordCache();
        modbusUtil.setPlcName(plcParam.getPlcName());
        this.modbusUtil = modbusUtil;
        this.plcParam = plcParam;
        init(deviceBases);
    }

    /**
     * 获取网络地址
     *
     * @return
     */
    public NetAddress getNetAddress() {
        return netAddress;
    }

    private Plc(ModbusUtil modbusUtil) {
        if (plcParam == null) {
            modbusUtil.setPlcName("XXX");
        } else {
            modbusUtil.setPlcName(plcParam.getPlcName());
        }
        this.modbusUtil = modbusUtil;
    }

    /**
     * 更新缓存
     *
     * @return
     * @throws IOException
     */
    public void refreshCache() throws IOException {
        try {
            int start = this.plcParam.getStartNum();
            // 读取所有的点位
            int end = this.plcParam.getEndNum();
            int count = ModbusUtil.BuildReadModbusCommand(start, end);
            for (int i = 0; i < count; i++) {
                int readNum = (i + 1 == count) ? end - start - PLC_READ_MAX_NUM * i : PLC_READ_MAX_NUM;
                int copyNum = (i + 1 == count) ? end - start : PLC_READ_MAX_NUM * i;
                int[] plcStatus = this.getModbusUtil().getResult(plcParam.getPlcName() + " 更新PLC缓存", this.getClass(), start + PLC_READ_MAX_NUM * i, 0, readNum);
                this.getPlcCache().setPlcStatus(plcStatus, PLC_READ_MAX_NUM * i, copyNum, end - start);
            }
            this.getPlcCache().setUpdateTime(System.currentTimeMillis());
            setPlcStatus(Network.ON_LINE);
        } catch (IOException e) {
            setPlcStatus(Network.OFF_LINE);
            throw new IOException();
        }

    }

    /**
     * @param deviceBases 把所有的设备放进Map集合方便调用
     */
    private void init(List<DeviceBase> deviceBases) {
        for (DeviceBase deviceBase : deviceBases) {
            switch (deviceBase.getPlcDeviceType()) {
                case TURNOVER_AUTOMATIC_SYSTEM:
                    SystemOper taSystemOper = new TurnoverAutomaticSystemOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    taSystemOper.setPlc(this);
                    systemBaseName = taSystemOper;
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), taSystemOper);
                    deviceSystemCoordMap.put(deviceBase.getCoord(), taSystemOper);
                    break;
                case TURNOVER_MACHINE:
                    TurnoverOper turnover = new TurnoverOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    turnover.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), turnover);
                    deviceTurnoverMachineOperCoordMap.put(deviceBase.getCoord(), turnover);
                    ParamConfig.singleAutoDoor = true;
                    break;
                case SINGLE_AUTO_DOOR:
                    SingleAutoDoor singleAutoDoor = new SingleAutoDoor(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    singleAutoDoor.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), singleAutoDoor);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), singleAutoDoor);
                    deviceAutomaticDoorCoordMap.put(deviceBase.getCoord(), singleAutoDoor);
                    ParamConfig.singleAutoDoor = true;
                    break;
                case CHAIN_STATION:
                    StationOper station = new StationOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    station.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), station);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), station);
                    deviceStationCoordMap.put(deviceBase.getCoord(), station);
                    break;
                case PANASONIC_LIFT:
                case SIEMENS_HOIST:
                case TAMAGAWA_LIFTER:
                    LifterOper lifter = new LifterOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    lifter.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), lifter);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), lifter);
                    deviceLifterCoordMap.put(deviceBase.getCoord(), lifter);
                    if (deviceBase.getLocation().equals(Location.INSIDE)) {
                        Coord lifterCrood = new Coord(deviceBase.getCoord().getX(), deviceBase.getCoord().getY(), 1);
                        lifterCoordMap.put(deviceBase.getDeviceName(), lifterCrood);
                    }
                    break;
                case AUTOMATIC_LIFTER:
                    LifterOper twoDirectionRgvLifterOper = new TwoDirectionRgvLifterOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    twoDirectionRgvLifterOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), twoDirectionRgvLifterOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), twoDirectionRgvLifterOper);
                    deviceLifterCoordMap.put(deviceBase.getCoord(), twoDirectionRgvLifterOper);
                    if (deviceBase.getLocation().equals(Location.INSIDE)) {
                        Coord lifterCrood = new Coord(deviceBase.getCoord().getX(), deviceBase.getCoord().getY(), 1);
                        lifterCoordMap.put(deviceBase.getDeviceName(), lifterCrood);
                    }
                    break;
                case FORK_LIFTER:
                    ForkLifterOper forkLifterOper = new ForkLifterOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(),deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    // 设置货叉提升机的基本位移量数据
                    forkLifterOper.analyzeLifterInfoDis(deviceBase.getLifterLayerMap(),deviceBase.getCarLocationMap(),deviceBase.getPalletStatusMap());
                    forkLifterOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), forkLifterOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), forkLifterOper);
                    deviceLifterCoordMap.put(deviceBase.getCoord(), forkLifterOper);
                    if (deviceBase.getLocation().equals(Location.INSIDE)) {
                        Integer gridz = ForkLifterOper.getGridz(deviceBase.getCoord().getX(), deviceBase.getCoord().getY());
                        Coord lifterCrood = new Coord(deviceBase.getCoord().getX(), deviceBase.getCoord().getY(), gridz);
                        lifterCoordMap.put(deviceBase.getDeviceName(), lifterCrood);
                    }

                    Map<Location, Coord> coordMap = lifterLocationMap.get(forkLifterOper.getPlcId());
                    if (coordMap == null) {
                        coordMap = new HashMap<>();
                    }

                    coordMap.put(forkLifterOper.getLocation(), forkLifterOper.getCoord());
                    lifterLocationMap.put(forkLifterOper.getPlcId(), coordMap);
                    break;
                case SYSTEM:
                    SystemOper systemOper = new SystemOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    systemOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), systemOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), systemOper);
                    deviceSystemCoordMap.put(deviceBase.getCoord(), systemOper);
                    systemBaseName = systemOper;
                    break;
                case SHAPE_DETECTION:
                    ShapeDetectorOper shapeDetectorOper = new ShapeDetectorOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    shapeDetectorOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), shapeDetectorOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), shapeDetectorOper);
                    deviceShapeCoordMap.put(deviceBase.getCoord(), shapeDetectorOper);
                    break;
                case SCANNER:
                    SweepCodeEquipmentOper sweepCodeEquipmentOper = new SweepCodeEquipmentOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    sweepCodeEquipmentOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), sweepCodeEquipmentOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), sweepCodeEquipmentOper);
                    deviceScannerCoordMap.put(deviceBase.getCoord(), sweepCodeEquipmentOper);
                    break;
                case WEIGHT:
                    WeightingEquipmentOper weightingEquipmentOper = new WeightingEquipmentOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    weightingEquipmentOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), weightingEquipmentOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), weightingEquipmentOper);
                    deviceWeightCoordMap.put(deviceBase.getCoord(), weightingEquipmentOper);
                    break;
                case DSIHSTATION:
                    DismountingDiskMachineOper dismountingDiskMachineOper = new DismountingDiskMachineOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    dismountingDiskMachineOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), dismountingDiskMachineOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), dismountingDiskMachineOper);
                    deviceDishCoordMap.put(deviceBase.getCoord(), dismountingDiskMachineOper);
                    break;
                case TRANS_PLANTER_STATION:
                    TransplanterOper transplanterOper = new TransplanterOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    transplanterOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), transplanterOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), transplanterOper);
                    deviceTransCoordMap.put(deviceBase.getCoord(), transplanterOper);
                    break;
                case AUTOMATIC_DOOR:
                    AutomaticDoorOper automaticDoorOper = new AutomaticDoorOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    automaticDoorOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), automaticDoorOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), automaticDoorOper);
                    deviceAutomaticDoorCoordMap.put(deviceBase.getCoord(), automaticDoorOper);
                    break;
                case BUTTON:
                    ButtonOper buttonOper = new ButtonOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    buttonOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), buttonOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), buttonOper);
                    deviceButtonCoordMap.put(deviceBase.getCoord(), buttonOper);
                    break;
                case AUTO_TRAVERSING:
                    AutoTraversingOper autoTraversingOper = new AutoTraversingOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    autoTraversingOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), autoTraversingOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), autoTraversingOper);
                    deviceAutoTraversingOperCoordMap.put(deviceBase.getCoord(), autoTraversingOper);
                    deviceStationCoordMap.put(deviceBase.getCoord(), autoTraversingOper);
                    break;
                case AUTO_HOIST:
                    AutoHoistOper autoHoistOper = new AutoHoistOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    autoHoistOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), autoHoistOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), autoHoistOper);
                    deviceStationCoordMap.put(deviceBase.getCoord(), autoHoistOper);
                    deviceAutoHoistOperCoordMap.put(deviceBase.getCoord(), autoHoistOper);
                    break;
                case TOOTH_HOIST:
                    ToothHoistOper toothHoistOper = new ToothHoistOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    toothHoistOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), toothHoistOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), toothHoistOper);
                    deviceStationCoordMap.put(deviceBase.getCoord(), toothHoistOper);
                    deviceToothHoistOperCoordMap.put(deviceBase.getCoord(), toothHoistOper);
                    break;
                case FOLDING_MACHINE:
                    FoldingOper foldingOper = new FoldingOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    foldingOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), foldingOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), foldingOper);
                    deviceFoldingOperCoordMap.put(deviceBase.getCoord(), foldingOper);
                    break;
                case MONOMER_CONVEYOR:
                    MonomerConveyorOper monomerConveyorOper = new MonomerConveyorOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    monomerConveyorOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), monomerConveyorOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), monomerConveyorOper);
                    deviceStationCoordMap.put(deviceBase.getCoord(), monomerConveyorOper);
                    deviceMonomerConveyorCoordMap.put(deviceBase.getCoord(), monomerConveyorOper);
                    deviceShapeConveyorCoordMap.put(deviceBase.getCoord(), monomerConveyorOper);
                    break;
                case TRANS_PLANTER:
                    TransPlanter transPlanter = new TransPlanter(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    transPlanter.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), transPlanter);
//                    deviceBaseCoordMap.put(deviceBase.getCoord(), transPlanter);
                    deviceTransPlanterCoordMap.put(deviceBase.getCoord(), transPlanter);
                    deviceStationCoordMap.put(deviceBase.getCoord(), transPlanter);
                    break;
                case SHAPE_CONVEYOR:
                    throw new RuntimeException("请改用单体输送线");
                case SHAPE:
                    ShapeOper shapeOper = new ShapeOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    shapeOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), shapeOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), shapeOper);
                    deviceShapeCoordMap.put(deviceBase.getCoord(), shapeOper);
                    break;
                case SCAN:
                    ScanOper scanOper = new ScanOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    scanOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), scanOper);
                    deviceBaseCoordMap.put(deviceBase.getCoord(), scanOper);
                    deviceScanCoordMap.put(deviceBase.getCoord(), scanOper);
                    break;
                case LIFTER_BASE:
                    LifterBaseOper lifterBaseOper = new LifterBaseOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    lifterBaseOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), lifterBaseOper);
                    break;
                case LIFTER_SYSTEM:
                    LifterSystemOper lifterSystemOper = new LifterSystemOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    lifterSystemOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), lifterSystemOper);
                    break;
                case LIFTER_STATION:
                case LIFTER_LEFT_STATION:
                case LIFTER_RIGHT_STATION:
                    LifterStationOper lifterStationOper = new LifterStationOper(deviceBase.getPlcDeviceType(),
                            deviceBase.getStartNo(), deviceBase.getDeviceName(), deviceBase.getDeviceNo(), deviceBase.getCoord(),
                            deviceBase.getLocation(), deviceBase.getLockLocation(), deviceBase.getDeviceId(),
                            deviceBase.getGridzMax(), deviceBase.getGridzRelative(), deviceBase.getPlcId());
                    lifterStationOper.setPlc(this);
                    deviceBaseNameMap.put(deviceBase.getDeviceName(), lifterStationOper);
                    break;
                default:
                    throw new IllegalArgumentException("不存在的类型" + deviceBase.getPlcDeviceType());
            }
        }
    }

    /**
     * 获取PLC实例
     *
     * @param netAddress  网络地址对象（ip+port）
     * @param deviceBases 此PLC下面的所有设备集合
     * @return
     * @throws IOException
     */

    public static Plc getPlc(NetAddress netAddress, List<DeviceBase> deviceBases, PlcParam plcParam) throws IOException {
        Plc plc = plcMap.get(netAddress);
        if (plc == null) {
            plc = new Plc(ModbusUtil.getModbus(new LongConnSendUtil(netAddress)), deviceBases, plcParam);
            plcMap.put(netAddress, plc);
        }
        return plc;
    }

    public static void putPLCAutomaticDoor(String key, String val) {
        ConcurrentHashMap<String, String> concurrentHashMap = PLC_AUTOMATIC_DOOR_CACHE.get(key);
        if (concurrentHashMap == null) {
            concurrentHashMap = new ConcurrentHashMap<>();
            PLC_AUTOMATIC_DOOR_CACHE.put(key, concurrentHashMap);
        }
        concurrentHashMap.put(val, val);
    }

    public synchronized static int pushPLCAutomaticDoor(String key, String val) {
        ConcurrentHashMap<String, String> concurrentHashMap = PLC_AUTOMATIC_DOOR_CACHE.get(key);
        if (concurrentHashMap == null) {
            concurrentHashMap = new ConcurrentHashMap<>();
            PLC_AUTOMATIC_DOOR_CACHE.put(key, concurrentHashMap);
        }
        concurrentHashMap.remove(val);
        return concurrentHashMap.size();
    }

    /**
     * 获取PLC实例
     *
     * @param netAddress 网络地址对象（ip+port）
     * @return
     * @throws IOException
     */

    public static Plc getPlc(NetAddress netAddress) throws IOException {
        Plc plc = plcMap.get(netAddress);
        if (plc == null) {
            plc = new Plc(ModbusUtil.getModbus(new LongConnSendUtil(netAddress)));
        }
        return plc;
    }

    public static Plc getPlcByNetAddress(NetAddress netAddress) {
        Plc plc = plcMap.get(netAddress);
        return plc;
    }

    public ModbusUtil getModbusUtil() {
        return modbusUtil;
    }

    public PlcWordCache getPlcCache() {
        return plcCache;
    }

    public Network getPlcStatus() {
        return plcStatus;
    }

    public void setPlcStatus(Network plcStatus) {
        this.plcStatus = plcStatus;
    }

    public static void checkPLCInterrupt(String key, String msg) {
        String value = PLC_INTERRUPT_CACHE.get(key);
        if (StringUtils.isEmpty(value)) {
            log.error("PLC中断：" + key + ", In ->" + msg);
            throw new PLCInterruptException("PLC中断：" + key + ", In ->" + msg);
        }
    }
}
